﻿using System;
using System.Collections.Generic;
using System.Text;
using FunctionalCLR.Core;

namespace Zove.Query {
    public class QueryParser {
        private string source;

        private Lexer lexer = null;

        public QueryParser(string source) {
            this.source = source;
            this.lexer = new Lexer(source);
        }

        Token t = null;

        public Query Parse() {
            Query d = new Query(source);
            t = lexer.NextToken();

            while (t.TokenType == TokenType.Identifier) {
                switch (t.Value) {
                    case ";":
                        break;
                    case "select":
                        d.Select = ParseExpressions();
                        break;
                    case "where":
                        d.Where = ParseWhere();
                        break;
                    case "from":
                        d.From = ParseFrom();
                        break;
                    case "assert":
                        d.Assert = ParseExpressions();
                        break;
                    case "import":
                        break;
                    default:
                        throw new Exception(
                            string.Format("Token is not as expected {0}", 
                            t.Value));
                }
            }

            return d;
        }

        public List<string> ParseExpressions() {
            int braceCount = 0;
            StringBuilder buff = new StringBuilder();
            List<string> s = new List<string>();

            t = lexer.NextToken();
            while (!IsKeyword(t.Value)) {
                buff.Append(t.Value);
                t = lexer.NextToken();
                switch (t.TokenType) {
                    case TokenType.LeftBrace:
                        braceCount++;
                        break;
                    case TokenType.RightBrace:
                        braceCount--;
                        break;
                    case TokenType.Comma:
                        if (braceCount == 0) {
                            s.Add(buff.ToString());
                            t = lexer.NextToken();

                            buff = new StringBuilder();
                        }
                        break;
                    default:
                        break;
                }
            }
            s.Add(buff.ToString());
            if (braceCount != 0) {
                throw new Exception();
            }

            return s;
        }

        public bool IsKeyword(string k) {
            return k == "where" || k == "select" || k == "from" || k == ";";
        }

        public List<string> ParseSelect() {
            StringBuilder buff = new StringBuilder();
            List<string> s = new List<string>();

            t = lexer.NextToken();
            while (!IsKeyword(t.Value)) {
                buff.Append(t.Value);
                t = lexer.NextToken();
                if (t.Value == ",") {
                    s.Add(buff.ToString());
                    t = lexer.NextToken();

                    buff = new StringBuilder();
                }
            }
            s.Add(buff.ToString());

            return s;
        }

        public Dictionary<string, string> ParseWhere() {
            List<string> where = ParseExpressions();
            Dictionary<string, string> w = new Dictionary<string, string>();

            foreach (string s in where) {
                string[] p = s.Split('=');
                w.Add(p[0], p[1]);
            }

            return w;
        }

        public string ParseFrom() {
            t = lexer.NextToken();
            string v = t.Value;
            t = lexer.NextToken();

            return v;
        }
    }
}
